import { getNanoid, halt } from '@/utils';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import axios from 'axios';
import { createHash } from 'crypto';
import dayjs from 'dayjs';
import path from 'path';
import mime from 'mime-types';

@Injectable()
export class CaeeService {
    private readonly apiUrl: string;
    private readonly bizId: string;
    private readonly appId: string;
    private readonly appKey: string;
    constructor(private readonly config: ConfigService) {
        this.apiUrl = this.config.get('caee.apiUrl');
        this.bizId = this.config.get('caee.bizId');
        this.appId = this.config.get('caee.appId');
        this.appKey = this.config.get('caee.appKey');
    }

    public get AppId() {
        return this.appId;
    }

    public async generateSeriesNo() {
        return await getNanoid(15);
    }

    public async pre(data: any) {
        return await this.post('/be-asset/api/v1/assets/pre', data);
    }

    public async registration(data: any) {
        return await this.post('/be-asset/api/v1/assets/registration', data);
    }

    public async status(data: any) {
        return await this.post('/be-asset/api/v1/assets/status', data);
    }

    public async getImageInfo(url: string) {
        try {
            const response = await axios.get(url, { responseType: 'stream' });
            const parsedUrl = new URL(url);
            const fileName = path.basename(parsedUrl.pathname);
            const fileExtension = path.extname(fileName).toLowerCase().slice(1);

            const toBase64 = (stream) =>
                new Promise((resolve, reject) => {
                    const chunks = [];
                    stream.on('data', (chunk) => chunks.push(chunk));
                    stream.on('error', reject);
                    stream.on('end', () => {
                        const buffer = Buffer.concat(chunks);
                        resolve(buffer.toString('base64'));
                    });
                });

            const base64Str = await toBase64(response.data);

            return {
                fileName,
                mediaType: mime.lookup(fileExtension) || 'image/jpeg',
                base64Str,
            };
        } catch (error) {
            console.error('Error fetching image:', error);
            throw error;
        }
    }

    private async sign({ nonce, ts, body }: any): Promise<string> {
        return new Promise((r) => {
            const bodySign = createHash('sha256').update(body).digest('hex');
            const sign = createHash('sha256')
                .update(
                    `${this.appId}${this.bizId}${bodySign}${nonce}${ts}${this.appKey}`,
                )
                .digest('hex');
            r(
                `appId=${this.appId}&bizId=${this.bizId}&ts=${ts}&nonce=${nonce}&sign=${sign}`,
            );
        });
    }

    private async post(url: string, data: any) {
        const nonce = await getNanoid(32);
        const ts = dayjs().unix().toString();
        const body = JSON.stringify(data);
        const sign = Buffer.from(await this.sign({ nonce, ts, body })).toString(
            'base64',
        );
        return await axios
            .post(`${this.apiUrl}${url}`, data, {
                headers: {
                    Authorization: `Aksk ${sign}`,
                    'Content-Type': 'application/json',
                },
            })
            .then((res) => res.data)
            .catch((e) => {
                console.error(e);
                return halt(e.response?.data?.msg ?? '未知错误');
            });
    }
}
